using System;
using System.Collections.Generic;
using System.Linq;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

using GameTypes;
using Camera;
using Input;
using Physics;
using Renderer;

//#if DEBUG
using DebugLibrary;
//#endif

namespace WindowsGame
{
	/// <summary>
	/// This is the main type for your game
	/// </summary>
	public class Game : Microsoft.Xna.Framework.Game
	{
		ContentManager content;
		GraphicsDeviceManager graphics;

		CameraService cameraService;
		InputService inputService;

		ObjectManager objectManager;

		private GameObject[] Objects = new GameObject[100];

		public Game()
		{
			graphics = new GraphicsDeviceManager(this);

			this.IsFixedTimeStep = false;

			graphics.PreferredBackBufferHeight = 720;
			graphics.PreferredBackBufferWidth = 1280;
			graphics.PreferMultiSampling = true;
			//graphics.SynchronizeWithVerticalRetrace = false;

			graphics.ApplyChanges();

			Content.RootDirectory = "Content";

			content = new ContentManager(this.Services);
			this.Services.AddService(typeof(ContentManager), content);

			Components.Add(new Input.Input(this));
			Components.Add(new Camera.Camera(this));
			Components.Add(new Physics.Physics(this));
			Components.Add(new Renderer.Renderer(this));

			PluginLoader.LoadPlugins("Plugins", this, Components);

			#if DEBUG
			Components.Add(new DebugLibrary.DebugLibrary(this));
			#endif

		}

		/// <summary>
		/// Allows the game to perform any initialization it needs to before starting to run.
		/// This is where it can query for any required services and load any non-graphic
		/// related content.  Calling base.Initialize will enumerate through any components
		/// and initialize them as well.
		/// </summary>
		protected override void Initialize()
		{

			System.Console.Out.WriteLine("Initializing...");

			// TODO: Add your initialization logic here
			this.Services.AddService(typeof(ObjectManager), new ObjectManager());

			this.inputService = (InputService)this.Services.GetService(typeof(InputService));
			this.cameraService = (CameraService)this.Services.GetService(typeof(CameraService));

			this.objectManager = (ObjectManager)this.Services.GetService(typeof(ObjectManager));

			base.Initialize();
			
			System.Console.Out.WriteLine("Initialized");
			
		}

		/// <summary>
		/// LoadContent will be called once per game and is the place to load
		/// all of your content.
		/// </summary>
		protected override void LoadContent()
		{
			System.Console.Out.WriteLine("Loadind content...");

			content.RootDirectory = "Content";

			for (int i = 0; i < 100; ++i)
			{
				this.Objects[i] = new GameObject("text object " + i);
				this.Objects[i].setModel(content.Load<Model>("Cube_10"));
				this.Objects[i].setPosition(new Vector3(0, 30 + i * 30, 0));
				this.Objects[i].setOrientation(Matrix.Identity * Matrix.CreateRotationX(1));

				this.objectManager.add(this.Objects[i]);

				((PhysicsService)this.Services.GetService(typeof(PhysicsService))).addObject(this.Objects[i]);
			}
		   
			System.Console.Out.WriteLine("Content loaded");
		}

		/// <summary>
		/// UnloadContent will be called once per game and is the place to unload
		/// all content.
		/// </summary>
		protected override void UnloadContent()
		{
			System.Console.Out.WriteLine("Unloadind content...");

			// TODO: Unload any non ContentManager content here
			content.Unload();
			//base.UnloadContent();

			System.Console.Out.WriteLine("Content unloaded");
		}

		/// <summary>
		/// Allows the game to run logic such as updating the world,
		/// checking for collisions, gathering input, and playing audio.
		/// </summary>
		/// <param name="gameTime">Provides a snapshot of timing values.</param>
		protected override void Update(GameTime gameTime)
		{

			if (!this.IsActive)
			{
				base.Update(gameTime);
				return;
			}

			// Allows the game to exit
			if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
			{
				this.Exit();
				return;
			}

			if (Keyboard.GetState().GetPressedKeys().Contains(Keys.Escape))
			{
				this.Exit();
				return;
			}

			// TODO: Add your update logic here
			this.cameraService.moveForwardBack(this.inputService.getMoveForwardBack());
			this.cameraService.moveLeftRight(this.inputService.getMoveLeftRight());
			this.cameraService.rotate(this.inputService.getRotationLeftRight());

			base.Update(gameTime);
		 
		}

		/// <summary>
		/// This is called when the game should draw itself.
		/// </summary>
		/// <param name="gameTime">Provides a snapshot of timing values.</param>
		protected override void Draw(GameTime gameTime)
		{

			GraphicsDevice.Clear(Color.CornflowerBlue);
			
			DepthStencilState depthState = new DepthStencilState();
			depthState.DepthBufferEnable = true;
			depthState.DepthBufferWriteEnable = true;
			GraphicsDevice.DepthStencilState = depthState;

			base.Draw(gameTime);

		}

	}

}
